/**
 * Created by wust on 2019-10-25 14:11:15
 * Copyright © 2019 wust. All rights reserved.
 */
package com.sc.admin.core.api.open.user;


import com.alibaba.fastjson.JSONObject;
import com.sc.admin.core.service.SysMenuService;
import com.sc.admin.core.service.SysResourceService;
import com.sc.admin.core.service.SysUserService;
import com.sc.common.annotations.OpenApi;
import com.sc.common.annotations.OperationLog;
import com.sc.common.context.DefaultBusinessContext;
import com.sc.common.dto.WebResponseDto;
import com.sc.common.entity.admin.account.SysAccount;
import com.sc.common.entity.admin.user.SysUser;
import com.sc.common.enums.ApplicationEnum;
import com.sc.common.enums.OperationLogEnum;
import com.sc.common.util.CommonUtil;
import com.sc.common.util.MyStringUtils;
import com.sc.common.util.RC4;
import com.sc.common.util.cache.DataDictionaryUtil;
import com.sc.common.util.cache.SpringRedisTools;
import com.sc.mq.producer.Producer4routingKey;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author: wust
 * @date: Created in 2019-10-25 14:11:15
 * @description: APP扫码登录
 *
 */
@Api(tags = {"开放接口~web员工扫码登陆"})
@OpenApi
@RequestMapping("/api/open/v1/WebUserLoginByQrCodeOpenApi")
@RestController
public class WebUserLoginByQrCodeOpenApi extends WebUserLoginBase {
    static Logger logger = LogManager.getLogger(WebUserLoginByQrCodeOpenApi.class);

    @Autowired
    private SpringRedisTools springRedisTools;

    @Autowired
    private SysUserService sysUserServiceImpl;

    @Autowired
    private SysMenuService sysMenuServiceImpl;

    @Autowired
    private SysResourceService sysResourceServiceImpl;

    @Autowired
    private Producer4routingKey producer4routingKey;

    @Autowired
    private Environment environment;


    @Override
    protected SpringRedisTools getSpringRedisTools() {
        return springRedisTools;
    }

    @Override
    protected SysMenuService getSysMenuServiceImpl() {
        return sysMenuServiceImpl;
    }

    @Override
    protected SysResourceService getSysResourceServiceImpl() {
        return sysResourceServiceImpl;
    }

    @Override
    protected WebResponseDto validateAndGetUser(String var1, String var2, String code, String message, String checkCodeRC4){
        WebResponseDto responseDto = new WebResponseDto();
        if(MyStringUtils.isBlank(MyStringUtils.null2String(code))){
            responseDto.setFlag(WebResponseDto.INFO_WARNING);
            responseDto.setMessage("扫码登录失败，非法的请求。" );
            logger.warn("扫码登录失败，缺少参数[code]");


            JSONObject jsonObject1 = new JSONObject();
            jsonObject1.put("code", WebResponseDto.INFO_WARNING);
            jsonObject1.put("message","扫码登录失败，非法的请求。" );

            String exchangeName = environment.getProperty("spring.rabbitmq.qrcodelogin4server2app.exchange.name ");
            String routingKey = environment.getProperty("spring.rabbitmq.qrcodelogin4server2app.routing-key");
            producer4routingKey.send(exchangeName,routingKey,jsonObject1);
            return responseDto;
        }



        if(MyStringUtils.isBlank(MyStringUtils.null2String(message))){
            responseDto.setFlag(WebResponseDto.INFO_WARNING);
            responseDto.setMessage("扫码登录失败，非法的请求。" );
            logger.warn("扫码登录失败，缺少参数[message]");


            JSONObject jsonObject1 = new JSONObject();
            jsonObject1.put("code", WebResponseDto.INFO_WARNING);
            jsonObject1.put("message","扫码登录失败，非法的请求。" );
            String exchangeName = environment.getProperty("spring.rabbitmq.qrcodelogin4server2app.exchange.name ");
            String routingKey = environment.getProperty("spring.rabbitmq.qrcodelogin4server2app.routing-key");
            producer4routingKey.send(exchangeName,routingKey,jsonObject1);
            return responseDto;
        }


        if(MyStringUtils.isBlank(MyStringUtils.null2String(checkCodeRC4))){
            responseDto.setFlag(WebResponseDto.INFO_WARNING);
            responseDto.setMessage("扫码登录失败，非法的请求。" );
            logger.warn("扫码登录失败，缺少参数[checkCodeRC4]");


            JSONObject jsonObject1 = new JSONObject();
            jsonObject1.put("code", WebResponseDto.INFO_WARNING);
            jsonObject1.put("message","扫码登录失败，非法的请求。" );
            String exchangeName = environment.getProperty("spring.rabbitmq.qrcodelogin4server2app.exchange.name ");
            String routingKey = environment.getProperty("spring.rabbitmq.qrcodelogin4server2app.routing-key");
            producer4routingKey.send(exchangeName,routingKey,jsonObject1);
            return responseDto;
        }



        String lang = "";

        if(WebResponseDto.INFO_SUCCESS.equals(code)) {
            String checkCode = RC4.decry_RC4(checkCodeRC4, ApplicationEnum.QRCode_LOGIN_RC4_KEY.getStringValue());
            String[] checkCodes = checkCode.split("=");
            if (checkCodes.length != 3) {
                responseDto.setFlag(WebResponseDto.INFO_WARNING);
                responseDto.setMessage("扫码登录失败，非法的请求。");
                logger.warn("扫码登录失败，校验码格式不正确");


                JSONObject jsonObject1 = new JSONObject();
                jsonObject1.put("code", WebResponseDto.INFO_WARNING);
                jsonObject1.put("message", "扫码登录失败，非法的请求。");
                String exchangeName = environment.getProperty("spring.rabbitmq.qrcodelogin4server2app.exchange.name ");
                String routingKey = environment.getProperty("spring.rabbitmq.qrcodelogin4server2app.routing-key");
                producer4routingKey.send(exchangeName, routingKey, jsonObject1);
                return responseDto;
            }


            /**
             * 由于app传过来的数据格式为：clientId=uuid=loginName
             * 因此需要截取出clientId=uuid
             */
            String checkCode1 = checkCode.substring(0, checkCode.lastIndexOf("="));
            String checkCode2 = RC4.encry_RC4_string(checkCode1, ApplicationEnum.QRCode_LOGIN_RC4_KEY.getStringValue());
            if (!springRedisTools.hasKey(checkCode2)) {
                responseDto.setFlag(WebResponseDto.INFO_WARNING);
                responseDto.setMessage("扫码登录失败，二维码信息已经过期。");
                logger.warn("扫码登录失败，二维码信息已经过期。");


                JSONObject jsonObject1 = new JSONObject();
                jsonObject1.put("code", WebResponseDto.INFO_WARNING);
                jsonObject1.put("message", "扫码登录失败，二维码信息已经过期。");
                String exchangeName = environment.getProperty("spring.rabbitmq.qrcodelogin4server2app.exchange.name ");
                String routingKey = environment.getProperty("spring.rabbitmq.qrcodelogin4server2app.routing-key");
                producer4routingKey.send(exchangeName, routingKey, jsonObject1);
                return responseDto;
            }

            lang = springRedisTools.getByKey(checkCode2).toString();
            springRedisTools.deleteByKey(checkCode2);


            /**
             * 登录
             */
            String loginName = checkCodes[3];

            SysAccount account = DataDictionaryUtil.getAccountByCode(loginName);
            if(account == null) {
                responseDto.setFlag(WebResponseDto.INFO_WARNING);
                responseDto.setMessage("扫码登录失败，系统不存在该账号。"); // 不应提示太明确，防止恶意碰撞攻击
                logger.warn("扫码登录失败，系统不存在该账号[{}]。", loginName);

                JSONObject jsonObject1 = new JSONObject();
                jsonObject1.put("code", WebResponseDto.INFO_WARNING);
                jsonObject1.put("message", "扫码登录失败，该账号没有注册。");
                String exchangeName = environment.getProperty("spring.rabbitmq.qrcodelogin4server2app.exchange.name ");
                String routingKey = environment.getProperty("spring.rabbitmq.qrcodelogin4server2app.routing-key");
                producer4routingKey.send(exchangeName, routingKey, jsonObject1);
                return responseDto;
            }


            Map<String,Object> map = new HashMap<>(2);
            map.put("account",account);
            map.put("lang",lang);
            if("A101701".equals(account.getType())){ // 管理员，只存在account表
            }else if("A101703".equals(account.getType())){ // 员工
                SysUser user = sysUserServiceImpl.selectByPrimaryKey(account.getId());
                map.put("user",user);
            }else if("A101705".equals(account.getType())){ // 客户登录，暂时不支持客户登录web系统
                responseDto.setFlag(WebResponseDto.INFO_WARNING);
                responseDto.setMessage("您无权登录系统");
                return responseDto;
            }
            responseDto.setObj(map);
        }else{
            responseDto.setFlag(WebResponseDto.INFO_WARNING);
            responseDto.setMessage("扫码登录失败：" + message);
        }
        return responseDto;
    }

    /**
     * 二维码值格式：clientId=uuid
     * @param clientId
     * @param lang
     * @return
     */
    @ApiOperation(value = "扫码登陆：获取二维码", httpMethod = "GET")
    @ApiImplicitParams({
            @ApiImplicitParam(name="clientId",value="客户端标识",required=true,paramType="query"),
            @ApiImplicitParam(name="lang",value="语言（如zh-CN）",required=true,paramType="query")
    })
    @OperationLog(moduleName= OperationLogEnum.MODULE_COMMON,businessName="获取手机扫码登录二维码",operationType= OperationLogEnum.Login)
    @RequestMapping(value = "/getAppLoginQRCode",method = RequestMethod.GET)
    public WebResponseDto getAppLoginQRCode(@RequestParam String clientId, @RequestParam String lang) {
        WebResponseDto responseDto = new WebResponseDto();

        String checkCode = clientId + "=" + UUID.randomUUID().toString() ;
        String checkCodeRC4 = RC4.encry_RC4_string(checkCode, ApplicationEnum.QRCode_LOGIN_RC4_KEY.getStringValue());
        springRedisTools.addData(checkCodeRC4,lang,5L, TimeUnit.MINUTES);
        responseDto.setObj(checkCodeRC4);
        return responseDto;
    }


    /**
     *
     * @param code
     * @param message
     * @param checkCodeRC4
     * @return
     */
    @ApiOperation(value = "App登陆：员工通过App扫码登陆", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name="code",value="结果标识，成功或失败，如：SUCCESS，ERROR",required=true,paramType="query"),
            @ApiImplicitParam(name="message",value="当code不等于SUCCESS时的消息",required=true,paramType="query"),
            @ApiImplicitParam(name="checkCodeRC4",value="检查码",required=true,paramType="query")
    })
    @OperationLog(moduleName= OperationLogEnum.MODULE_COMMON,businessName="Web登陆：员工通过手机App扫码登陆",operationType= OperationLogEnum.Login)
    @RequestMapping(value = "/login",method = RequestMethod.POST)
    public WebResponseDto login(@RequestParam("code") String code, @RequestParam("message") String message, @RequestParam("checkCodeRC4") String checkCodeRC4) {
        WebResponseDto responseDto = new WebResponseDto();

        WebResponseDto validateAndGetUserResponseDto = validateAndGetUser("","",code,message,checkCodeRC4);
        if(!WebResponseDto.INFO_SUCCESS.equals(validateAndGetUserResponseDto.getFlag())){
            return validateAndGetUserResponseDto;
        }


        Map map = (Map) validateAndGetUserResponseDto.getObj();
        SysAccount account = map.get("account") == null ? null : (SysAccount)map.get("account");
        SysUser user = map.get("user") == null ? null : (SysUser)map.get("user");
        String lang = map.get("lang").toString();

        DefaultBusinessContext.getContext().setDataSourceId(ApplicationEnum.DEFAULT.name());

        String[] tokens = createToken(user.getLoginName());
        if (tokens.length != 2) {
            responseDto.setFlag(WebResponseDto.INFO_WARNING);
            responseDto.setMessage("登录失败");
        }else{
            Long accountId = account.getId();
            String accountType = account.getType();
            String permissionType = CommonUtil.getPermissionType(accountType,user == null ? "" : user.getType());
            
            
            /**
             * 解析获取当前登录用户的相关资源
             */
            final Map<String,Object> mapValue = new HashMap<>();
            appendMenuToUserContext(mapValue,accountId,accountType,permissionType,lang);
            appendMenuNameToUserContext(mapValue,permissionType,lang);
            appendAccountToUserContext(mapValue,account);
            appendUserToUserContext(mapValue,user);
            appendProjectToUserContext(mapValue,accountId);
            appendLangToUserContext(mapValue,lang);
            appendTokenToUserContext(mapValue,tokens[1]);

            responseDto.setObj(getResponseResource(accountType,permissionType,mapValue));


            /**
             * 将用户登录相关信息存储到缓存，以便解析作为上下文
             */
            String redisKey = tokens[0];
            springRedisTools.addMap(redisKey,  mapValue, ApplicationEnum.X_AUTH_TOKEN_EXPIRE_TIME.getIntValue(), TimeUnit.MINUTES);
        }


        /**
         * 通知app登录成功
         */
        JSONObject jsonObject1 = new JSONObject();
        jsonObject1.put("code", WebResponseDto.INFO_SUCCESS);
        jsonObject1.put("message","" );
        String exchangeName = environment.getProperty("spring.rabbitmq.qrcodelogin4server2app.exchange.name ");
        String routingKey = environment.getProperty("spring.rabbitmq.qrcodelogin4server2app.routing-key");
        producer4routingKey.send(exchangeName,routingKey,jsonObject1);

        return responseDto;
    }
}
